#include <string>
#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
//条件变量,初始化规则与互斥锁一致
pthread_cond_t g_cond = PTHREAD_COND_INITIALIZER;

void *thread_routine(void *argc)
{
    while (true)
    {

        //阻塞住等待被唤醒//条件变量必须搭配锁一起使用
        //在等待进入阻塞前会自动解锁,再恢复时会自动申请锁
        //如果取消线程,很容易造成死锁问题:
        // 1.所有线程被唤醒,等待锁,一个线程拿到锁,没来得及解锁,立马被取消
        //  其他线程一直等待死锁,此时无法被取消.
        // 2.再等待条件的时候,被取消,会自动被唤醒,拿到锁,然后立即取消 ->1
        pthread_mutex_lock(&g_mutex);
        pthread_cond_wait(&g_cond, &g_mutex);
        cout << "thread_" << reinterpret_cast<size_t>(argc) << " id: " << pthread_self() << endl;
        pthread_mutex_unlock(&g_mutex);
        // sleep(6);
        //取消前先唤醒所有线程,一个线程拿到锁,解锁,睡眠,另一个拿到锁,解锁,睡眠...
        //全部线程在这个时机被取消,此时锁时解开的,不会有问题.
    }
    //总结:问题一: 线程在等条件变量的时候被取消,cancel调用成功返回0,线程自动被唤醒,拿到锁后立刻被退出,不会自动解锁
    //     问题二: 线程在等待锁的时候被取消,cancel调用成功返回0,线程会等拿到锁后立刻退出,不会自动解锁
    //     为什么只退出一个:唤醒全部线程后一个线程拿到锁,然后直接退出,其他线程都在等待死锁的时候被cancel->问题二.
    //      解决方案一:用sleep函数控制时序,唤醒所有线程后,每一个线程解锁后休眠(防止再次进入cond_wait引发问题一),在所有子线程休眠时取消线程.
    //      解决方案二:每次调用cancel前主动解锁,每个线程都能自动唤醒,拿到锁,退出,解决了问题一.
    //      解决方案三:不使用cancel 用全局布尔变量控制循环(最优)
}
int main()
{
// pthread_cond_init(&g_cond,nullptr);
#define threads_num 4
    pthread_t threads[threads_num];
    for (int i = 0; i < threads_num; i++)
    {
        pthread_create(threads + i, nullptr, thread_routine, reinterpret_cast<void *>(i + 1));
    }
    char input = char();
    while (true)
    {
        cout << "请输入(n/q):> ";
        cin >> input;
        if (input == 'n')
        {
            //唤醒队头的线程
            pthread_cond_signal(&g_cond);
            usleep(1000);
        }
        else
        {
            //唤醒全部线程
            //pthread_cond_broadcast(&g_cond);
            for (int i = threads_num - 1; i >= 0; i--)
            {
                pthread_mutex_unlock(&g_mutex);
                cout << pthread_cancel(threads[i]) << endl;
                usleep(123); //这里还是要小睡一下,防止执行太快了
            }
            break;
        }
    }
    cout << "--------------" << endl;
    for (int i = 0; i < threads_num; i++)
    {
        pthread_join(threads[i], nullptr);
        cout << "joined:" << i << endl;
    }
    return 0;
}